
import copy
from typing import List

from parsel import Selector
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.alert import Alert
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait as Wait
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys

from src import settings
from src.util import common_util
from src.util import flogger

class BrowserDriver(webdriver.Chrome):

    log = flogger.Flogger().get_logger(__name__)

    def __init__(self, proxy=None, options: List[str] = None, options_dict=None, page_load_strategy='normal',show_auto_test: bool = True):
        chrome_options = webdriver.ChromeOptions()
        if proxy is not None:
            chrome_options.add_argument(f'--proxy-server={proxy}')
        if not show_auto_test:
            user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
            chrome_options.add_argument(f'user-agent={user_agent}')
            chrome_options.add_experimental_option("useAutomationExtension", False)
            chrome_options.add_experimental_option("excludeSwitches", ["enable-logging", "enable-automation"])
        if options is not None:
            for option in options:
                chrome_options.add_argument(option)
        chrome_options.add_argument("--enable-javascript")
        chrome_options.page_load_strategy = page_load_strategy
        if options_dict is not None:
            for k, v in options_dict.items():
                chrome_options.add_experimental_option(k, v)
        service = Service(executable_path=settings.PATH_WEB_DRIVE_DIR + "/" + settings.CHROME_DRIVER_EXE)
        super().__init__(options=chrome_options,service=service)

        # js注入
        js = common_util.load_text_from_file(settings.PATH_WEB_DRIVE_DIR + "/stealth.min.js")
        self.execute_cdp_cmd(
            "Page.addScriptToEvaluateOnNewDocument", {"source": js}
        )

    def to_selector(self) -> Selector:
        html = copy.deepcopy(self.page_source)
        return Selector(text=html)

    def switch_to_window(self, num: int):
        """切换窗体
        窗体序号，切换到新窗体
        -1.切换到旧窗体

        Args:
            num (int): 窗体编号
        """
        self.switch_to.window(self.window_handles[num])

    def find_element_by_xpath(self, xpath) -> WebElement|None:
        try:
            return self.find_element(by=By.XPATH, value=xpath)
        except Exception:
            return None

    def find_element_by_id(self, xpath) -> WebElement|None:
        try:
            return self.find_element(by=By.ID, value=xpath)
        except Exception:
            return None

    def find_elements_by_xpath(self, xpath) -> List[WebElement]:
        try:
            return self.find_elements(by=By.XPATH, value=xpath)
        except Exception:
            return []

    def wait_element_by_xpath(self, xpath: str, wait_time: int = 5) -> WebElement|None:
        try:
            return Wait(self, wait_time).until(
                    EC.presence_of_element_located((By.XPATH, xpath))
                )
        except Exception :
            return None

    def wait_alter_element(self,wait_time: int = 5) -> Alert|None:
        try:
            Wait(self, wait_time).until(EC.alert_is_present())
            return self.switch_to.alert
        except Exception:
            return None

    def wait_element_by_id(self, xpath: str, wait_time: int = 5) -> WebElement|None:
        try:
            return Wait(self, wait_time).until(
                    EC.presence_of_element_located((By.ID, xpath))
                )
        except Exception:
            return None

    def mouse_to_element(self,element: WebElement):
        ActionChains(self).move_to_element(element).perform()

    def mouse_click(self,element: WebElement):
        ActionChains(self).move_to_element(element).click(element).perform()

    def key_return(self,element: WebElement):
        element.send_keys(Keys.RETURN)

